package com.swift.monitor.core.proxy;

import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;

public class JvmManagement {

    private static RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();

    @SuppressWarnings("restriction")
    private static com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory
        .getOperatingSystemMXBean();

    private static MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
    
    private static ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    //-javaagent
    private static Instrumentation instrumentation;
    
    /**
     *  这个方法先于主方法(main)执行
     * @param args
     * @param inst
     */
    public static void premain(String args, Instrumentation inst) {
        instrumentation = inst;
    }
    /**
     *  直接计算当前对象占用空间大小，包括当前类及超类的基本类型实例字段大小、
     *  引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;
     *  但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小
     *
     * @param o 需要计算内存的对象
     * @return 返回内存大小
     */
    public static long sizeOf(Object o) {
        if(instrumentation==null) {
            return 0;//不异常防式本地启动
        }
        return instrumentation.getObjectSize(o);
    }
    
    /**
     * 递归计算当前对象占用空间总大小，包括当前类和超类的实例字段大小以及实例字段引用对象大小
     * 注意：这个方法如果你看不懂也没关系，会用就行
     *
     * @param objP
     * @return
     * @throws IllegalAccessException
     */
    public static long fullSizeOf(Object objP) throws IllegalAccessException {
        Set<Object> visited = new HashSet<Object>();
        Deque<Object> toBeQueue = new ArrayDeque<>();
        toBeQueue.add(objP);
        long size = 0L;
        while (toBeQueue.size() > 0) {
            Object obj = toBeQueue.poll();
            //sizeOf的时候已经计基本类型和引用的长度，包括数组
            size += skipObject(visited, obj) ? 0L : sizeOf(obj);
            Class<?> tmpObjClass = obj.getClass();
            if (tmpObjClass.isArray()) {
                //[I , [F 基本类型名字长度是2
                if (tmpObjClass.getName().length() > 2) {
                    for (int i = 0, len = Array.getLength(obj); i < len; i++) {
                        Object tmp = Array.get(obj, i);
                        if (tmp != null) {
                            //非基本类型需要深度遍历其对象
                            toBeQueue.add(Array.get(obj, i));
                        }
                    }
                }
            } else {
                while (tmpObjClass != null) {
                    Field[] fields = tmpObjClass.getDeclaredFields();
                    for (Field field : fields) {
                        if (Modifier.isStatic(field.getModifiers())   //静态不计
                                || field.getType().isPrimitive()) {    //基本类型不重复计
                            continue;
                        }
 
                        field.setAccessible(true);
                        Object fieldValue = field.get(obj);
                        if (fieldValue == null) {
                            continue;
                        }
                        toBeQueue.add(fieldValue);
                    }
                    tmpObjClass = tmpObjClass.getSuperclass();
                }
            }
        }
        return size;
    }
 
    /**
     * String.intern的对象不计；计算过的不计，也避免死循环
     *
     * @param visited
     * @param obj
     * @return
     */
    private static boolean skipObject(Set<Object> visited, Object obj) {
        if (obj instanceof String && obj == ((String) obj).intern()) {
            return true;
        }
        return visited.contains(obj);
    }
    /**
     * Java虚拟机启动以来的峰值实时线程数
     * @return
     */
    public static int getPeakThreadCount() {
        return threadMXBean.getPeakThreadCount();
    }
    /**
     * 返回已创建和已启动的线程总数
     * @return
     */
    public static long getTotalStartedThreadCount() {
        return threadMXBean.getTotalStartedThreadCount();
    }
    /**
     * 死锁的线程的ID数组
     * @return
     */
    public static long[] findDeadlockedThreads() {
        return threadMXBean.findDeadlockedThreads();
    }
    /**
     * 死锁的线程数
     * @return
     */
    public static int findDeadlockedThreadCount() {
        long[] ids = findDeadlockedThreads();
        if (ids == null) {
            return 0;
        } else {
            return ids.length;
        }
    }
    /**
     * 返回当前的活动线程数，包括守护进程和非守护进程线程
     * @return
     */
    public static int getRunThreadCount() {
        return threadMXBean.getThreadCount();
    }
    /**
     * 申请的堆内存最大值xmx
     * @return
     */
    public static long getMaxHeapMemorySize() {
        return memoryMXBean.getHeapMemoryUsage().getMax();
    }

    /**
     * 获取堆已使用的内存大小
     */
    public static long getUsedHeapMemorySize() {
        return memoryMXBean.getHeapMemoryUsage().getUsed();
    }
    /**
     * 申请的堆内存最小值xms
     * @return
     */
    public static long getInitHeapMemorySize() {
        return memoryMXBean.getHeapMemoryUsage().getInit();
    }
    /**
     * 非堆内存使用值
     * @return
     */
    public static long getUsedNonHeapMemorySize() {
        return memoryMXBean.getNonHeapMemoryUsage().getUsed();
    }
    /**
     * 非堆内存申请值最少XX:PermSize等
     * @return
     */
    public static long getInitNonHeapMemorySize() {
        return memoryMXBean.getNonHeapMemoryUsage().getInit();
    }

    /**
     * 非堆内存申请值最少XX:MaxPermSize等
     * @return
     */
    public static long getMaxNonHeapMemorySize() {
        return memoryMXBean.getNonHeapMemoryUsage().getMax();
    }
    /**
     * 获取进程ID
     */
    public static int getProcessId() {
        String name = runtimeMXBean.getName();
        String id = name.split("@")[0];
        return Integer.parseInt(id);
    }
    /**
     * jvm启动时间
     * @return
     */
    public static long getStartTime() {
        return runtimeMXBean.getStartTime();
    }
    /**
     * 返回最后一分钟的系统平均负载
     * @return
     */
    public static double getSystemLoadAverage() {
        return operatingSystemMXBean.getSystemLoadAverage();
    }
    /**
     * 返回最后一分钟的应用平均负载
     * @return
     */
    @SuppressWarnings("restriction")
    public static double getProcessLoadAverage() {
        return operatingSystemMXBean.getProcessCpuLoad();
    }
    /**
     * 获取当前的CPU时间
     */
    @SuppressWarnings("restriction")
    public static long getProcessCpuTime() {
        return operatingSystemMXBean.getProcessCpuTime();
    }
    /**
     * 获取物理内存总大小
     * @return
     */
    @SuppressWarnings("restriction")
    public static long getTotalPhysicalMemorySize() {
        return operatingSystemMXBean.getTotalPhysicalMemorySize();
    }
    /**
     * 获取空闲的物理内存
     * @return
     */
    @SuppressWarnings("restriction")
    public static long getFreePhysicalMemorySize() {
        return operatingSystemMXBean.getFreePhysicalMemorySize();
    }
    /**
     * 获取虚拟内存总大小
     * @return
     */
    @SuppressWarnings("restriction")
    public static long getTotalSwapSpaceSize() {
        return operatingSystemMXBean.getTotalSwapSpaceSize();
    }
    /**
     * 获取虚拟内存使用大小
     * @return
     */
    @SuppressWarnings("restriction")
    public static long getFreeSwapSpaceSize() {
        return operatingSystemMXBean.getFreeSwapSpaceSize();
    }
    
}
